#!/bin/sh
# Copyright (c) Huawei Technologies Co., Ltd. 2012-2023. All rights reserved.
# Description: Oracle common functions.
#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
. "${SCRIPT_ROOT_PATH}"/common_sbin_func.sh

# define error code 

ERROR_SCRIPT_EXEC_FAILED=5
ERROR_RESULT_FILE_NOT_EXIST=6
ERROR_TMP_FILE_IS_NOT_EXIST=7
ERROR_PATH_WRONG=8
ERROR_PARAM_WRONG=9
ERROR_DB_USERPWD_WRONG=10
ERROR_INSTANCE_NOSTART=11
ERROR_PARAM_INVALID=12
ERROR_INSUFFICIENT_WRONG=15
ERROR_BACKUP_INVALID=19
ERROR_ORACLE_NOARCHIVE_MODE=24
ERROR_ORACLE_OVER_ARCHIVE_USING=25
ERROR_ORACLE_APPLICATION_OVER_MAX_LINK=28
ERROR_ORACLE_DB_ALREADY_INBACKUP=29
ERROR_ORACLE_DB_INHOT_BACKUP=30
ERROR_ORACLE_DB_ALREADYRUNNING=31
ERROR_ORACLE_DB_ALREADYMOUNT=32
ERROR_ORACLE_DB_ALREADYOPEN=33
ERROR_ORACLE_DB_ARCHIVEERROR=34
ERROR_ORACLE_NOT_MOUNTED=40
ERROR_ORACLE_NOT_OPEN=41
ERROR_ORACLE_TRUNCATE_ARCHIVELOG_FAILED=42
ERROR_ORACLE_TNS_PROTOCOL_ADAPTER=43
ERROR_ORACLE_NOT_INSTALLED=44
ERROR_ORACLE_ANOTHER_STARTING=45
ERROR_ORACLE_DB_BUSY=46
ERROR_ORACLE_DB_NOT_COMPLETE_SHUTDOWN=51
ERROR_ORACLE_BACKUP_FAILED=56
ERROR_ORACLE_EXESQL_FAILED=61
ERROR_ORACLE_EXERMAN_FAILED=62
ERROR_ORACLE_EXEASMCMD_FAILED=63
ERROR_ORACLE_RECOVERPATH_NOT_EXIT=64
ERROR_ORACLE_DISKGROUP_NOT_EXIT=65
ERROR_ORACLE_FILE_RESTORE_COPY_FAILED=66
ERROR_SCRIPT_ORACLEHOME_LOST=68
ERROR_SCRIPT_ORACLEBASE_LOST=69

ERROR_LOST_FULL_BACKUP=91
ERROR_ORACLE_HAS_LOG_LOST=92
ERROR_PRIMARY_STANDBY_DIFFERENT=147
ERROR_ORACLE_VERSION_DISMATCH=186

# define instance status
INSTANCE_OFFLINE=1
INSTANCE_ONLINE=0
INSTANCE_LOGIN_OS_TYPE=1
INSTANCE_LOGIN_DB_TYPE=0
SCRIPTPID_TMP_FILE_PREFIX=scriptpid_tmp
SCRIPTPID_FILE="${TMP_PATH}/${SCRIPTPID_TMP_FILE_PREFIX}${PID}"
ORACLE_MARK="/###ORACLE_MARK###/"

ORACLE_SQLPLUS_ERROR_MAP="ORA-12560~TNS protocol adapter error.~${ERROR_ORACLE_TNS_PROTOCOL_ADAPTER}#\
ORA-01034~ORACLE not available.~${ERROR_INSTANCE_NOSTART}#\
ORA-00020~can not connect, maximum number of processes exceeded.~${ERROR_ORACLE_APPLICATION_OVER_MAX_LINK}#\
ORA-01017~invalid username/password; logon denied.~${ERROR_DB_USERPWD_WRONG}#\
ORA-01031~insufficient privileges.~${ERROR_INSUFFICIENT_WRONG}#\
ORA-01123~cannot start online backup; media recovery not enabled.~${ERROR_ORACLE_NOARCHIVE_MODE}#\
ORA-01146~cannot start online backup - file 1 is already in backup.~${ERROR_ORACLE_DB_ALREADY_INBACKUP}#\
ORA-01142~cannot end online backup - none of the files are in backup.~${ERROR_ORACLE_DB_INHOT_BACKUP}#\
ORA-01081~cannot start already-running.~${ERROR_ORACLE_DB_ALREADYRUNNING}#\
ORA-01100~database already mounted.~${ERROR_ORACLE_DB_ALREADYMOUNT}#\
ORA-01531~a database already open by the instance.~${ERROR_ORACLE_DB_ALREADYOPEN}#\
ORA-01507~database not mounted.~${ERROR_ORACLE_NOT_MOUNTED}#\
ORA-01109~database not open.~${ERROR_ORACLE_NOT_OPEN}#\
ORA-10997~another startup/shutdown operation of this instance inprogress.~${ERROR_ORACLE_ANOTHER_STARTING}#\
ORA-01154~database busy. Open, close, mount, and dismount not allowed now.~${ERROR_ORACLE_DB_BUSY}#\
ORA-01012~database is not completely shut down.~${ERROR_ORACLE_DB_NOT_COMPLETE_SHUTDOWN}#\
ORA-01034~database is not completely shut down.~${ERROR_ORACLE_DB_NOT_COMPLETE_SHUTDOWN}#
ORA-15001~diskgroup not mount or not exist.~${ERROR_ORACLE_ASM_DISKGROUP_NOTMOUNT}#"


LOG_IS_VALID="(RESETLOGS_ID=(select RESETLOGS_ID from v\$database_incarnation where STATUS='CURRENT')) and (deleted = 'NO') and (ARCHIVED='YES') and (STATUS != 'U')"

# Description: Get oracle install tpye
# Arguments: None
# Globals: DBISCLUSTER single=0 rac=1 single_asm=2
# Returns: None
check_oracle_install_type()
{
    DBISCLUSTER=0
    ORACLE_LOC=/etc/oracle/ocr.loc
    if [ "${SYS_NAME}" = "HP-UX" ] || [ "${SYS_NAME}" = "SunOS" ]; then
        ORACLE_LOC=/var/opt/oracle/ocr.loc
    fi

    if [ -f "${ORACLE_LOC}" ]; then
        CLUSTER_FLAG=`cat "${ORACLE_LOC}" | grep "local_only" | ${MYAWK} -F "=" '{print $2}'`
        CLUSTER_FLAG=`echo "${CLUSTER_FLAG}" | tr [a-z] [A-Z]`
        if [ "${CLUSTER_FLAG}" = "FALSE" ]; then
            DBISCLUSTER=1  # oracle rac
        elif [ "${CLUSTER_FLAG}" = "TRUE" ]; then
            DBISCLUSTER=2  # oracle restart(single + asm)
        else
            log_warn "Unknown oracle type: ${CLUSTER_FLAG} set default type single 0 "
        fi
    else
        log_warn "Can not find file: ${ORACLE_LOC} set default type single 0"
    fi
    log_info "Check oracle type [DBISCLUSTER=${DBISCLUSTER}] success."
}

# Description: Check Whether the Oracle Database Is Installed
# Arguments: None
# Globals: ORACLE_IS_INSTALL 0 is not install 1 is install  INVENTORY_PATH
# Returns: None
check_oracle_is_install()
{
    if [ -n "${ORA_DB_USER}" ]; then
        tmp_file="${STMP_PATH}/get_oracle_home_path_tmp_${PID}.txt"
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} echo \$ORACLE_HOME" >"${tmp_file}" 2>&1
        if [ $? -ne 0 ]; then
            log_error "Get oracle home env cmd execute failed, error:`cat "${tmp_file}"`"
            delete_file "${tmp_file}"
            exit ${ERROR_ORACLE_NOT_INSTALLED}
        fi

        # 删除自定义字符串
        delete_oracle_mark "${tmp_file}"

        IN_ORACLE_HOME=`cat "${tmp_file}"`
        delete_file "${tmp_file}"
        if [ -z "${IN_ORACLE_HOME}" ]; then
            log_error "Get environment IN_ORACLE_HOME var is not exit."
            exit ${ERROR_ORACLE_NOT_INSTALLED}
        fi
        if [ ! -d "${IN_ORACLE_HOME}" ]; then
            log_error "Get environment IN_ORACLE_HOME var is not a directory."
            exit ${ERROR_ORACLE_NOT_INSTALLED}
        fi
        log_info "Get oracle home environment success value IN_ORACLE_HOME=${IN_ORACLE_HOME}"
        return
    fi
    INVENTORY_LOC=/etc/oraInst.loc
    if [ "${SYS_NAME}" = "HP-UX" ] || [ "${SYS_NAME}" = "SunOS" ]; then
        INVENTORY_LOC=/var/opt/oracle/oraInst.loc
    fi
    if [ "${SYS_NAME}" = "AIX" ]; then
        return
    fi
    # check file exists
    if [ ! -f "${INVENTORY_LOC}" ]; then
        log_error "Oracle install file oraInst.loc is not exists, not install oracle."
        exit "${ERROR_ORACLE_NOT_INSTALLED}"
    fi
    
    INVENTORY_PATH=`cat "${INVENTORY_LOC}" | grep "inventory_loc" | ${MYAWK} -F "=" '{print $2}'`
    if [ -z "${INVENTORY_PATH}" ]; then
        log_error "Can not get inventory_loc path, not install oracle."
        exit "${ERROR_ORACLE_NOT_INSTALLED}"
    fi
    
    if [ ! -d "${INVENTORY_PATH}" ]; then
        log_error "${INVENTORY_PATH} diretory not exists, oracle is not installed."
        exit "${ERROR_ORACLE_NOT_INSTALLED}"
    fi
}

# Description: get oracle database install user
# Arguments: None
# Globals: ORA_DB_USER user name ORA_DB_GROUP user group
# Returns: None
get_oracle_user()
{
    if [ -z "${ORA_DB_USER}" ]; then
        ORA_DB_USER=`ls -l /etc/oratab | $MYAWK '{print $3}'`
        if [ ${?} -ne 0 ] || [ -z "${ORA_DB_USER}" ]; then
            log_warn "Get oracle user failed, set default user oracle."
            ORA_DB_USER="oracle"
        fi
    fi
    if [ -z "${ORA_DB_GROUP}" ]; then
        ORA_DB_GROUP=`groups "${ORA_DB_USER}" | ${MYAWK} '{print $3}'`
        if [ ${?} -ne 0 ] || [ -z "${ORA_DB_GROUP}" ]; then
            log_warn "Get oracle user group failed, set default group oinstall."
            ORA_DB_GROUP="oinstall"
        fi
    fi
    log_info "Get oracle user:[${ORA_DB_USER}] group:[${ORA_DB_GROUP}] info success"
}

# Description: get oracle gird install user
# Arguments: None
# Globals: ORA_GRID_USER user name ORA_GRID_GROUP user group
# Returns: None
get_grid_user()
{
    if [ -z "${ORA_GRID_USER}" ]; then
        crshome=`cat /etc/oracle/olr.loc | grep "crs_home" | $MYAWK -F "=" '{print $NF}'`
        if [ ${?} -ne 0 ] || [ -z "$crshome" ]; then
            log_warn "Get crshome failed, set default user grid."
            ORA_GRID_USER=grid
        else
            ORA_GRID_USER=`ls -l "${crshome}"/bin/oracle | $MYAWK '{print $3}'`
            if [ ${?} -ne 0 ] || [ -z "${ORA_GRID_USER}" ]; then
                log_warn "Get grid user by ${crshome} failed, set default user grid."
                ORA_GRID_USER=grid
            fi
        fi
    fi
    if [ -z "${ORA_GRID_GROUP}" ]; then
        ORA_GRID_GROUP=`groups "${ORA_GRID_USER}" | ${MYAWK} '{print $3}'`
        if [ ${?} -ne 0 ] || [ -z "${ORA_GRID_GROUP}" ]; then
            log_warn "Get grid user group failed, set default group oinstall."
            ORA_GRID_GROUP="oinstall"
        fi
    fi
    log_info "Get grid user:[${ORA_GRID_USER}] group:[${ORA_GRID_GROUP}] info successs"
}

# Description: get oracle user shell type
# Arguments: None
# Globals: ORACLE_SHELLTYPE ORACLE_SHELL_MODE
# Returns: 0 for success, other nums for fail
get_oracle_user_shell_type()
{
    get_oracle_user
    ORACLE_SHELLTYPE=`get_user_shell_type "${ORA_DB_USER}"`
    ret_code=$?
    if [ $ret_code -ne 0 ] || [ -z "${ORACLE_SHELLTYPE}" ]; then
        log_error "Get oracle shell type failed"
        return $ret_code
    fi
    if [ "${ORACLE_SHELLTYPE}" = "bash" ]; then
        ORACLE_SHELL_MODE="-l"
    fi
    log_info "Get oracle type:[${ORACLE_SHELLTYPE}], mode:[${ORACLE_SHELL_MODE}] info success "
}

# Description: get grid user shell type
# Arguments: None
# Globals: GRID_SHELLTYPE GRID_SHELL_MODE
# Returns: 0 for success, other nums for fail
get_grid_user_shell_type()
{
    get_grid_user
    GRID_SHELLTYPE=`get_user_shell_type "${ORA_GRID_USER}"`
    ret_code=$?
    if [ $ret_code -ne 0 ] || [ -z "${GRID_SHELLTYPE}" ]; then
        log_error "Get grid shell type failed"
        return $ret_code
    fi
    if [ "${GRID_SHELLTYPE}" = "bash" ]; then
        GRID_SHELL_MODE="-l"
    fi
    log_info "Get grid type: ${GRID_SHELLTYPE}, mode: ${GRID_SHELL_MODE} info success "
}

# Description: get oracle user ORACLE_BASE env var
# Arguments: None
# Globals: IN_ORACLE_BASE 
# Returns: 0 for success, other nums for fail
get_oracle_base_path()
{
    tmp_file="${STMP_PATH}/get_oracle_base_path_tmp_${PID}.txt"
    get_oracle_user
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} echo \$ORACLE_BASE" >"${tmp_file}" 2>&1

    if [ $? -ne 0 ]; then
        log_error "Get oracle base env cmd execute failed, error:`cat "${tmp_file}"`"
        delete_file "${tmp_file}"
        exit ${ERROR_SCRIPT_ORACLEBASE_LOST}
    fi
    delete_oracle_mark "${tmp_file}"
    IN_ORACLE_BASE=`cat "${tmp_file}"`
    delete_file "${tmp_file}"
    if [ -z "${IN_ORACLE_BASE}" ]; then
        log_error "Get ORACLE_BASE environment failed, ORACLE_BASE is none."
        exit ${ERROR_SCRIPT_ORACLEBASE_LOST}
    fi
    log_info "Get oracle base environment success value IN_ORACLE_BASE=${IN_ORACLE_BASE} "
}

# Description: get oracle user ORACLE_HOME env var
# Arguments: None
# Globals: IN_ORACLE_HOME 
# Returns: 0 for success, other nums for fail
get_oracle_home_path()
{
    tmp_file="${STMP_PATH}/get_oracle_home_path_tmp_${PID}.txt"
    get_oracle_user
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} echo \$ORACLE_HOME" >"${tmp_file}" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Get oracle home env cmd execute failed, error:`cat "${tmp_file}"`"
        delete_file "${tmp_file}"
        exit ${ERROR_SCRIPT_ORACLEHOME_LOST}
    fi
    delete_oracle_mark "${tmp_file}"
    IN_ORACLE_HOME=`cat "${tmp_file}"`
    delete_file "${tmp_file}"
    if [ -z "${IN_ORACLE_HOME}" ]; then
        log_error "Get environment IN_ORACLE_HOME var is not exit."
        exit ${ERROR_SCRIPT_ORACLEHOME_LOST}
    fi
    log_info "Get oracle home environment success value IN_ORACLE_HOME=${IN_ORACLE_HOME}"
}

# Description: get grid user ORACLE_HOME env var
# Arguments: None
# Globals: IN_GRID_HOME 
# Returns: 0 for success, other nums for fail
get_grid_home_path()
{
    get_grid_user
    tmp_file="${STMP_PATH}/get_oracle_home_path_tmp_${PID}.txt"
    IN_GRID_HOME=""
    su - "${ORA_GRID_USER}" "${GRID_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_GRID_ENV} echo \$ORACLE_HOME " > "${tmp_file}" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Get grid home env cmd execute failed, error:`cat "${tmp_file}"`"
        delete_file "${tmp_file}"
    else
        delete_oracle_mark "${tmp_file}"
        IN_GRID_HOME=`cat "${tmp_file}"`
        delete_file "${tmp_file}"
    fi
    if [ -z "$IN_GRID_HOME" ]; then
        crshome=`cat /etc/oracle/olr.loc | grep "crs_home" | $MYAWK -F "=" '{print $NF}'`
        if [ ${?} -ne 0 ] || [ -z "$crshome" ]; then
            log_warn "Get crshome failed, set default user grid."
        else
            GRID_ORACLE_HOME="${crshome}"
            IN_GRID_HOME="${crshome}"
            log_info "get_grid_oracle_home: ${GRID_ORACLE_HOME}"
        fi
    fi
    if [ -z "$IN_GRID_HOME" ]; then
        log_error "IN_GRID_HOME Environment var is not exit."
        exit ${ERROR_SCRIPT_ORACLEHOME_LOST}
    fi
    log_info "Get grid home environment success value IN_GRID_HOME=$IN_GRID_HOME."
}

# Description: get oracle install version
# Arguments: None
# Globals: ORA_VERSION  ORA_PREVERSION
# Returns: 0 for success, other nums for fail
get_oracle_version()
{
    tmp_file="${STMP_PATH}/get_oracle_version_tmp_${PID}.txt"
    get_oracle_user
    # ----------get oracle version---------
    echo "exit" | su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} sqlplus /nolog " > "${tmp_file}" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Get oracle version failed, error:`cat "${tmp_file}"`"
        delete_file "${tmp_file}"
        return "${RETURN_INVALID}"
    fi
    delete_oracle_mark "${tmp_file}"
    version_info=`cat "${tmp_file}"`
    # 优先查找包含Version的行
    version_from_version_line=$(echo "${version_info}" | grep "Version" | $MYAWK '{print $2}')
    if [ -n "$version_from_version_line" ]; then
        # 如果找到了包含Version的行，使用其第二个字段
        echo "$version_from_version_line" > "${tmp_file}" 2>&1
    else
        # 没找到则使用原来的逻辑
        log_warn "The oracle version may be less than 19."
        echo "${version_info}" | grep "SQL\*Plus: Release" | $MYAWK '{print $3}' > "${tmp_file}" 2>&1
    fi
    if [ $? -ne 0 ]; then
        log_error "Get oracle version failed, error:`cat "${tmp_file}"`"
        delete_file "${tmp_file}"
        return "${RETURN_INVALID}"
    fi
    ORA_VERSION=`cat "${tmp_file}"`
    delete_file "${tmp_file}"
    if [ -z "${ORA_VERSION}" ]; then
        log_error "Get oracle version failed"
        return "${RETURN_INVALID}"
    fi
    ORA_PREVERSION=`rd_substr "$ORA_VERSION" 1 2`
    ORA_PREVERSION_EXTEND=`rd_substr "$ORA_VERSION" 1 4 | tr -d '.'`
    log_info "Get oracle version(${ORA_VERSION}), preVersion(${ORA_PREVERSION}) success."
}

generate_oracle_export_cmd()
{
    get_oracle_user
    ORACLE_ENV_FILE=`get_user_env_file "${ORA_DB_RUN_USER}"`
    EXPORT_ORACLE_ENV=`generate_export_cmd "${ORACLE_ENV_FILE}" "oracle"`
    if [ -z "${EXPORT_ORACLE_ENV}" ]; then
        log_error "Generate oracle export cmd failed"
    fi
}

sqlplus_timeout()
{
    if [ ! "$1" = "-1" ]; then
        "$MONITOR_FILENAME" $$ sqlplus "$1" "${SCRIPT_ROOT_PATH}" >>"${LOG_FILE_NAME}" 2>&1 &
    fi
}

rman_timeout()
{
    if [ ! "$1" = "-1" ]; then
        "$MONITOR_FILENAME" $$ rman "$1" "${SCRIPT_ROOT_PATH}" >>"${LOG_FILE_NAME}" 2>&1 &
    fi
}
# Description: oracle user use sqlplus execute sql file
# Arguments: 
#           db_user=$1: have permisson execute oracle sql file user
#           db_pwd=$2: user password 
#           sql_file=$3: execute sql file abs path only oracle can modify this file
#           rst_file=$4: execute sql result info abs path only root can modify this file
#           instance_name=$5: execute sql instance name
#           timeout_second=$6: execute sql time limit unit second, -1 is not limit
#           is_silence=$7: sqlplus execute silence mode
# Globals: None
# Returns: 0 for success, other nums for fail
oracle_exe_sql()
{
    db_user=$1
    db_pwd=$2
    # only oracle can modify sql_file file
    sql_file=$3
    # only root can modify rst file
    rst_file=$4
    instance_name=$5
    # execute sql timeout -1 is not limit
    timeout_second=$6
    # 静默模式只显示结果信息
    is_silence=$7
    if [ "${is_silence}" -eq 1 ]; then
        silent_mode="-S"
    fi
    sqlplus_timeout "${timeout_second}"
    # 提取到外面进行 函数呢不做修改文件权限 oracle必须要有权限读取权限

    set_env_cmd=`generate_export_oracle_sid "${instance_name}"`
    if [ -z "${db_user}" ] || [ -z "${db_pwd}" ]; then
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${set_env_cmd} sqlplus -L ${silent_mode} '/ as sysdba' @'${sql_file}' " >"${rst_file}" 2>&1
        result_code=$?
        delete_oracle_mark "${rst_file}"
        # ~/.bash_profile 配置了stty erase ^H 时执行sql会出现stty:开头的内容
        if [ ${result_code} -eq 0 ]; then
          sed -i '/^stty:/d' "${rst_file}"
        fi
    else
        echo \"${db_pwd}\" | su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${set_env_cmd} sqlplus -L ${silent_mode} '${db_user} as sysdba' @'${sql_file}' " >"${rst_file}" 2>&1
        result_code=$?
        delete_oracle_mark "${rst_file}"
        # ~/.bash_profile 配置了stty erase ^H 时执行sql会出现stty:开头的内容
        if [ ${result_code} -eq 0 ]; then
          sed -i '/^stty:/d' "${rst_file}"
        fi
        # 因为密码是输入进去的，会导致结果文件第一行为空行
        sed '1d' "${rst_file}" >"${rst_file}".bak
        mv "${rst_file}".bak "${rst_file}"
    fi
    if [ ${result_code} -ne 0 ]; then
        log_error "Execute oracle sqlplus cmd failed, cmd ret code ${result_code}"
        result_code=$ERROR_SCRIPT_EXEC_FAILED
    fi
    get_sql_error_info "${rst_file}" "$result_code" 1
    return $?
}

# Description: grid user use sqlplus execute sql file
# Arguments: 
#           db_user=$1: have permisson execute grid sql file user
#           db_pwd=$2: user password 
#           sql_file=$3: execute sql file abs path only oracle can modify this file
#           rst_file=$4: execute sql result info abs path only root can modify this file
#           instance_name=$5: execute sql instance name
#           timeout_second=$6: execute sql time limit unit second, -1 is not limit
#           is_silence=$7: sqlplus execute silence mode
# Globals: None
# Returns: 0 for success, other nums for fail
asm_exe_sql()
{
    asm_user=$1
    asm_pwd=$2
    sql_file=$3
    # only root can modify rst file
    rst_file=$4
    instance_name=$5
    timeout_second=$6

    sqlplus_timeout "${timeout_second}"

    str_set_env=`generate_export_grid_oracle_sid "${instance_name}"`
    if [ "$ORA_PREVERSION" -gt "11" ]; then
        asm_shell_type=${GRID_SHELLTYPE}
        asm_role="sysasm"
    else
        asm_shell_type=${ORACLE_SHELLTYPE}
        asm_role="sysdba"
    fi
    if [ -z "${asm_user}" ] || [ -z "${asm_pwd}" ]; then
        su - "${ORA_GRID_USER}" "${GRID_SHELLTYPE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_GRID_ENV} ${str_set_env} sqlplus -L '/ as ${asm_role}' @'${sql_file}' " > "${rst_file}" 2>&1
        result_code=$?
        delete_oracle_mark "${rst_file}"
        # ~/.bash_profile 配置了stty erase ^H 时执行sql会出现stty:开头的内容
        if [ ${result_code} -eq 0 ]; then
          sed -i '/^stty:/d' "${rst_file}"
        fi
    else
        echo "${asm_pwd}" | su - "${ORA_GRID_USER}" "${GRID_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_GRID_ENV} ${str_set_env} sqlplus -L '${asm_user} as ${asm_role}' @'${sql_file}' " > "${rst_file}" 2>&1
        result_code=$?
        delete_oracle_mark "${rst_file}"
        # ~/.bash_profile 配置了stty erase ^H 时执行sql会出现stty:开头的内容
        if [ ${result_code} -eq 0 ]; then
          sed -i '/^stty:/d' "${rst_file}"
        fi
        # 因为密码是输入进去的，会导致结果文件第一行为空行
        sed '1d' "${rst_file}" >"${rst_file}".bak
        mv "${rst_file}".bak "${rst_file}"
    fi
    if [ ${result_code} -ne 0 ]; then
        log_error "Execute oracle sqlplus cmd failed, ret code ${result_code}"
        result_code=$ERROR_SCRIPT_EXEC_FAILED
    fi
    get_sql_error_info "${rst_file}" "$result_code" 1
    return $?
}

# Description: grid user use sqlplus execute sql file
# Arguments: 
#           db_user=$1: have permisson execute grid sql file user
#           db_pwd=$2: user password 
#           sql_file=$3: execute sql file abs path only oracle can modify this file
#           rst_file=$4: execute sql result info abs path only root can modify this file
#           instance_name=$5: execute sql instance name
#           timeout_second=$6: execute sql time limit unit second, -1 is not limit
# Globals: GRID_SHELLTYPE IS_ENC_BK ORA_DB_USER ORACLE_SHELLTYPE EXPORT_ORACLE_ENV RMAN_ENC_SECTION
# Returns: 0 for success, other nums for fail

rman_exe_script()
{
    db_user=$1
    db_pwd=$2
    sql_file=$3
    rst_file=$4
    instance_name=$5
    timeout_second=$6
    enc_type=$7
    rman_timeout "${timeout_second}"

    str_set_env=`generate_export_oracle_sid "${instance_name}"`
    if [ "${IS_ENC_BK}" -ne 0 ] && [ "$enc_type" -eq 1 ]; then
        echo "${RMAN_ENC_SECTION}" > "${sql_file}".bk
        cat "${sql_file}" >> "${sql_file}".bk
        mv "${sql_file}".bk "${sql_file}"
        chown "${ORA_DB_USER}" "${sql_file}"
        chmod 700 "${sql_file}"
    fi
    if [ "${db_user}" = "" ] || [ "${db_pwd}" = "" ]; then
            su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${str_set_env} rman target '/' cmdfile '${sql_file}' " > "${rst_file}" 2>&1
            result_code=$?
            delete_oracle_mark "${rst_file}"
        else
            echo \"${db_pwd}\" | su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${str_set_env} rman target \"'${db_user}'\" cmdfile '${sql_file}' " > "${rst_file}" 2>&1
            result_code=$?
            delete_oracle_mark "${rst_file}"
    fi
    if [ ${result_code} -ne 0 ]; then
        log_error "Execute oracle rman cmd failed, ret code ${result_code}"
        result_code=$ERROR_SCRIPT_EXEC_FAILED
        get_sql_error_info "${rst_file}" "${result_code}" 0
        return $?
    fi
    return 0
}

# Description: check sqlplus result file have ORA error
# Arguments: sqlplus result file
# Globals: None
# Returns: 0 is success, other is fail
get_sql_error_info()
{
    result_file=$1
    index=1
    while true; do 
        error_info=`echo "${ORACLE_SQLPLUS_ERROR_MAP}" | $MYAWK -F "#" -v i="${index}" '{print $i}'`
        if [ -z "${error_info}" ]; then
            break
        fi
        error_oracle_code=`echo "$error_info" | ${MYAWK} -F "~" '{print $1}'`
        error_oracle_detail=`echo "$error_info" | ${MYAWK} -F "~" '{print $2}'`
        error_code=`echo "$error_info" | ${MYAWK} -F "~" '{print $3}'`
        error_num=`cat "${result_file}" | grep "${error_oracle_code}" | wc -l | $MYAWK '{print $1}'`
        if [ "${error_num}" -ne 0 ]; then
            log_error "Oracle sqlplus execute result file find error, ${error_oracle_detail}"
            write_error_info_to_file "${result_file}"
            return "${error_code}"
        fi
        index=`expr "$index" + 1`
    done

    #ORA-28002: the password will expire within 7 days
    #ORA-32004: obsolete and/or deprecated parameter(s) specified
    #ORA-32006: BACKGROUND_DUMP_DEST initialization parameter has been deprecated
    #ORA-32006: USER_DUMP_DEST initialization parameter has been deprecated
    #ORA-16136: Managed Standby Recovery not active
    while read line; do
        if [ "$3" -eq 1 ]; then
            echo "${line}" | grep -v "ORA-28002" | grep -v "ORA-32004" | grep -v "ORA-32006" | grep -v "ORA-16136" | grep "^ORA-"
            if [ $? -eq 0 ]; then
                log_error "Oracle exec sqlplus script failed"
                write_error_info_to_file "${result_file}"
                return "${ERROR_ORACLE_EXESQL_FAILED}"
            fi
        else
            echo "${line}" | grep "^RMAN-"
            if [ $? -eq 0 ]; then
                log_error "Oracle exec rman script failed"
                write_error_info_to_file "${result_file}"
                return "${ERROR_ORACLE_EXERMAN_FAILED}"
            fi
        fi
    done < "$result_file"
    return "$2"
}

# Description: get oracle instance auth type 
# Arguments: instance_name=$1 oracle instance name
# Globals: None
# Returns: -1 for fail, other nums for auth tyoe 0 is db 1 is os
get_instance_auth_type()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none canot get auth type"
        return 2
    fi
    check_oracle_auth_sql="${STMP_PATH}/check_oracle_auth_sql_${PID}.sql"
    check_oracle_auth_rst="${STMP_PATH}/check_oracle_auth_rst_${PID}.txt"
    echo "exit;" > "${check_oracle_auth_sql}"
    set_db_silence_sql "${check_oracle_auth_sql}"

    oracle_exe_sql "" "" "${check_oracle_auth_sql}" "${check_oracle_auth_rst}" "${instance_name}" 10 1
    ret_code=$?
    delete_file "${check_oracle_auth_sql}" "${check_oracle_auth_rst}"
    if [ ${ret_code} -ne 0 ]; then
        log_info "Instance ${instance_name} is DB auth type."
        delete_file "${STMP_PATH}/result_errordetail${PID}"
        return ${INSTANCE_LOGIN_DB_TYPE} # need password
    fi
    log_info "Instance ${instance_name} is OS auth type."
    return ${INSTANCE_LOGIN_OS_TYPE} # not need password
}

# Description: get asm instance auth type 
# Arguments: instance_name=$1 grid asm instance name
# Globals: None
# Returns: -1 for fail, other nums for auth tyoe 0 is db 1 is os
get_asm_auth()
{
    asm_instance_name=$1
    if [ -z "${asm_instance_name}" ]; then
        log_error "Asm instance name is none canot get asm auth type"
        return "2"
    fi
    get_asm_auth_sql="${STMP_PATH}/get_asm_auth_sql_${PID}.sql"
    get_asm_auth_rst="${STMP_PATH}/get_asm_auth_rst_${PID}.txt"
    echo "exit;" >> "${get_asm_auth_sql}"
    chown "${ORA_GRID_USER}" "${get_asm_auth_sql}"
    chmod 700 "${get_asm_auth_sql}"
    
    asm_exe_sql "" "" "${get_asm_auth_sql}" "${get_asm_auth_rst}" "${asm_instance_name}" 10 1
    ret_code=$?
    delete_file "${get_asm_auth_sql}" "${get_asm_auth_rst}"
    if [ $ret_code -ne 0 ]; then
        log_info "Get asm instance:[${instance_name}] is DB auth type ."
        return ${INSTANCE_LOGIN_DB_TYPE} # need password
    fi
    log_info "Get asm instance:[${instance_name}] is OS auth type ."
    return ${INSTANCE_LOGIN_OS_TYPE}
}

# Description: get oracle instance status 
# Arguments: instance_name=$1 db instance name
# Globals: None
# Returns: -1 for fail, other nums for instance status 0 is online 1 is offline
get_instance_process_status()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none canot get status"
        return "2"
    fi
    # ----------database status---------
    ps -aef | sed 's/ *$//g' | grep "ora_...._${instance_name}$" | grep -v "grep" >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        status=${INSTANCE_ONLINE} #online
    else
        status=${INSTANCE_OFFLINE} #offline
    fi
    log_info "Get oracle instance(${instance_name}) status(${status})"
    return ${status}
}

# Description: get oracle instance status 
# Arguments: instance_name=$1 db instance name 
# database_user=$2: if instance is db auth type need user else is none
# database_password=$3 if instance is db auth type need password else is none
# Globals: None
# Returns: 0 for success and echo db name, other nums for fail 
get_database_name()
{
    instance_name=$1
    database_user=$2
    database_password=$3
    auth_type=$4

    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not get database name"
        return "$RETURN_INVALID"
    fi

    # if database offine from config info get database name inaccuracy is not high 
    tmp_sql="${STMP_PATH}/get_database_name_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_name_rst_${PID}.txt"
    echo "set linesize 999;" > "${tmp_sql}"
    echo "select value from v\$parameter where name = 'db_unique_name' or name = 'db_name' order by name;" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    if [ "${auth_type}" -eq "${INSTANCE_LOGIN_OS_TYPE}" ] && [ -n "${database_password}" ]; then
      ret_code=`check_database_password "${database_user}" "${database_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 10 1`
    else
      oracle_exe_sql "${database_user}" "${database_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 10 1
      ret_code=$?
    fi
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get instance:[${instance_name}] database name failed ret=${ret_code}"
        delete_file "${tmp_rst}" "${tmp_sql}" "true"
        return ${ret_code}
    fi
    database_name=`cat "${tmp_rst}" | $MYAWK 'NR==1{print $1}'`
    database_name=`echo "${database_name}" | tr [A-Z] [a-z]`
    database_unique_name=`cat "${tmp_rst}" | $MYAWK 'NR==2{print $1}'`
    database_unique_name=`echo "${database_unique_name}" | tr [A-Z] [a-z]`
    delete_file "${tmp_rst}" "${tmp_sql}" "true"

    log_info "Get instance:[${instance_name}] database name:[${database_name}] database unique name:[${database_unique_name}]success"
    if [ "$database_name" -eq "$database_unique_name" ]; then
        echo "${database_name}"
    else
        echo "${database_unique_name}"
    fi
}

get_database_name_from_conf()
{
    db_list=`ls -l "${IN_ORACLE_BASE}/admin" | grep "^d" | $MYAWK '{print $NF}'`
    for db_name in ${db_list}; do
        log_info "Get database name [${db_name}] success "
        db_names="${db_names}${db_name};"
    done
    log_info "From conf get dbname[$db_names]"
    echo "$db_names"
}
get_database_status()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not get database status"
        return "${RETURN_INVALID}"
    fi
    database_user=$2
    database_password=$3

    tmp_sql="${STMP_PATH}/get_database_status_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_status_${PID}.rst"

    echo "select status from v\$instance;" > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    log_info "Exec SQL to get status of database."
    oracle_exe_sql "${database_user}" "${database_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    delete_file "${tmp_sql}" 
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get oracle instance status failed ret ${ret_code}, error is `cat "$tmp_rst"`"
        delete_file "${tmp_rst}"
        return ${ret_code}
    fi
    instance_status=`cat "${tmp_rst}"`
    log_info "INSTANCESTATUS=${instance_status}."
    delete_file "${tmp_rst}"
    echo "${instance_status}"
}

get_database_open_mode()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not get database open mode"
        return "${RETURN_INVALID}"
    fi
    database_user=$2
    database_password=$3

    tmp_sql="${STMP_PATH}/get_database_open_mode_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_open_mode_rst_${PID}.txt"

    echo "select open_mode from v\$database;" > "$tmp_sql" 
    echo "exit" >> "$tmp_sql"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${database_user}" "${database_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    delete_file "${tmp_sql}"
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get oracle instance open mode failed ret ${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_rst}"
        return ${ret_code}
    fi
    open_mode=`cat "${tmp_rst}"`
    log_info "open_mode=${open_mode}."
    delete_file "${tmp_rst}"
    echo "${open_mode}"
}

# Description: get oracle database uuid  
# Arguments: instance_name=$1 db instance name 
# database_user=$2: if instance is db auth type need user else is none
# database_password=$3 if instance is db auth type need password else is none
# Globals: None
# Returns: 0 for success and echo db uuid, other nums for fail
get_database_uuid()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not get database name"
        return "${RETURN_INVALID}"
    fi
    database_user=$2
    database_password=$3

    tmp_sql="${STMP_PATH}/get_database_uuid_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_uuid_rst_${PID}.txt"
    echo "set linesize 999;" > "${tmp_sql}"
    echo "select dbid from v\$database;" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${database_user}" "${database_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 10 1
    ret_code=$?
    delete_file "${tmp_sql}"
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get instance:[${instance_name}] database uuid failed, ret=${ret_code}, error info: `cat "${tmp_rst}"`"
        delete_file "${tmp_rst}"
        return ${ret_code}
    fi
    dbuuid=`cat "${tmp_rst}"`
    if [ -z "${dbuuid}" ]; then
        log_error "Get instance:[${instance_name}] db uuid failed is none"
        delete_file "${tmp_rst}"
        return "${RETURN_INVALID}"
    fi
    delete_file "${tmp_rst}"
    log_info "Get instance:[${instance_name}] database uuid:[${dbuuid}] success"
    echo "${dbuuid}"
    return
}

# Description: get oracle instance list
# Arguments: value_file=$1 will return instance list in file , only root can modify 
# Globals: None
# Returns: 0 for success and echo db uuid, other nums for fail
get_oracle_instance_list()
{
    log_info "Begin to read oracle instance list."
    value_file=$1
    if [ ! -f "${value_file}" ]; then
        touch "${value_file}"
        if [ $? -ne 0 ]; then
            log_error "Create return value file failed"
            return "${RETURN_INVALID}"
        fi
    fi
    tmp_file="${STMP_PATH}/get_oracle_instance_list_tmp_${PID}.txt"
    # query online database
    instance_list="`ps -ef | grep ora_...._ | grep -v grep | $MYAWK '{print $NF}' | $MYAWK -F"_...._" '{print $2}' | uniq`"
    for instance_name in ${instance_list}; do
        grep "^${instance_name}$" "${value_file}" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            continue
        fi
        echo "${instance_name}" >> "${value_file}"
    done
    log_info "Get oracle instance info success"
    return
}

# Description: get oracle instance list
# Arguments: value_file=$1 will return instance list in file , only root can modify 
# Globals: None
# Returns: 0 for success and echo db uuid, other nums for fail
check_pfile_have_disk_group()
{
    pfile_name=$1
    if [ ! -f "${pfile_name}" ]; then
        log_info "Pfile: ${pfile_name} not exists."
        return "${RETURN_INVALID}"
    fi

    tmp_file="${STMP_PATH}/get_pfile_tmp_${PID}.txt"
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; cat ${pfile_name}" > "${tmp_file}" 2>&1
    delete_oracle_mark "${tmp_file}"
    param_file_content= `cat "${tmp_file}"`
    delete_file "${tmp_file}"
    if [ -z "${param_file_content}" ]; then
        log_error "Get param file: ${param_file_content} content failed is none"
        return "${RETURN_INVALID}"
    fi

    for line in ${param_file_content}; do
        tmp_value=`echo "${line}" | tr [a-z] [A-Z]`
        echo "${tmp_value}" | grep "CONTROL_FILES="
        if [ $? -ne 0 ]; then
            continue
        fi

        tmp_value=`echo "${tmp_value}" | $MYAWK -F "=" '{print $2}' | sed 's/ //g'`
        echo "${tmp_value}" | grep "+"
        if [ $? -eq 0  ]; then
            return 1
        fi
    done
}

# Description: belong pfile or init file check db whether is asm instance
# Arguments: instance_name=$1
# Globals: None
# Returns: 1 is asm instance 0 is not asm instance -1 is failed
check_db_asm()
{
    instance_name=$1
    if [ -z "${instance_name}" ]; then
        log_info "${instance_name} is none can not get."
        return "${RETURN_INVALID}"
    fi
    check_database_paramfile_is_asm "${IN_ORACLE_HOME}/dbs/init${instance_name}.ora"
    if [ $? -eq 1 ]; then
        return ${?}
    fi

    check_database_paramfile_is_asm "${IN_ORACLE_HOME}/dbs/spfile${instance_name}.ora"
    if [ $? -eq 1 ]; then
        return $?
    fi
    return $?
}

# Description: add db sqlife silence sql and sql file will only oracle user modify
# Arguments: sql_file=$1
# Globals: None
# Returns: 0 is success other is fail 
set_db_silence_sql()
{
    sql_file=$1
    if [ -z "${sql_file}" ] || [ ! -f "${sql_file}" ]; then
        log_error "Sql file is none or not exits set db silence failed"
        return "${RETURN_INVALID}"
    fi
    echo "set pagesize 0" > "${sql_file}.bak"
    echo "set feedback off" >> "${sql_file}.bak"
    echo "set newpage none" >> "${sql_file}.bak"
    echo "set heading off" >> "${sql_file}.bak"
    cat "${sql_file}" >> "${sql_file}.bak"
    mv "${sql_file}.bak" "${sql_file}"
    chown "${ORA_DB_USER}" "${sql_file}"
    chmod 700 "${sql_file}"
}

# Description: add asm sqlife silence sql and sql file will only grid user modify
# Arguments: sql_file=$1
# Globals: None
# Returns: 0 is success other is fail 
set_asm_silence_sql()
{
    sql_file=$1
    if [ -z "${sql_file}" ] || [ ! -f "${sql_file}" ]; then
        log_error "Sql file is none or not exits set asm silence failed"
        return "${RETURN_INVALID}"
    fi
    echo "1i set pagesize 0" > "${sql_file}.bak"
    echo "1i set feedback off" >> "${sql_file}.bak"
    echo "1i set newpage none" >> "${sql_file}.bak"
    echo "1i set heading off" >> "${sql_file}.bak"
    cat "${sql_file}" >> "${sql_file}.bak"
    mv "${sql_file}.bak" "${sql_file}"
    chown "${ORA_GRID_USER}" "${sql_file}"
    chmod 700 "${sql_file}"
}

# need to get realy instance name
# not cluster, instance name is same as parameter
# cluster, instance name need to get instace number, eg. instance dbtest, dbtest1 or dbtest2
get_real_instance_name()
{
    instance_name=$1
    if [ "${DBISCLUSTER}" -eq 0 ] || [ "${DBISCLUSTER}" -eq 2 ]; then
        log_info "Database is single, real instance is ${instance_name} "
        echo "${instance_name}"
        return
    fi
    db_num=`ps -ef | grep -nE "^ora_...._${instance_name}$|ora_...._${instance_name}" | grep -v grep | $MYAWK '{print $NF}' | uniq | $MYAWK -F "_" '{print $NF}' | uniq | wc -l | $MYAWK '{print $1}'`
    if [ "${db_num}" -ne 1 ]; then
        log_warn "Instance ${instance_name} have invalid number not equal 1."
        echo "${instance_name}"
    else
        log_info "Instance ${instance_name} has one exist, get it's instance_name. "
        name=`ps -ef | grep -nE "^ora_...._${instance_name}$|ora_...._${instance_name}" | grep -v grep \
        | $MYAWK '{print $NF}' | uniq | grep "^ora_pmon" | $MYAWK -F "ora_pmon_" '{print $NF}' | uniq`
        echo "${name}"
    fi
}

check_disk_group_exits()
{
    dg_name=$1
    asm_instance_name=$2
    if [ -z "${dg_name}" ] || [ -z "${asm_instance_name}" ]; then
        log_error "Param is invalid dg name or asm instance is none"
        return "${RETURN_INVALID}"
    fi
    db_name=`echo "${db_name}" | tr [a-z] [A-Z]`
    set_env_cmd=`generate_export_grid_oracle_sid "${asm_instance_name}"`
    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} asmcmd ls ${dg_name}" >/dev/null 2>&1
    return $?
}

check_path_in_disk_group()
{
    path=$1
    asm_instance_name=$2
    if [ -z "${path}" ] || [ -z "${asm_instance_name}" ]; then
        log_error "Param is invalid path name or asm instance is none"
        return "${RETURN_INVALID}"
    fi
    set_env_cmd=`generate_export_grid_oracle_sid "${asm_instance_name}"`
    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} asmcmd ls ${path}" >/dev/null 2>&1
    return $?
}

create_dir()
{
    dirArry=`echo "$1" | sed 's/;/ /g'`
    for dir in ${dirArry}; do
        if [ "`rd_substr "${dir}" 1 1`" = "/" ]; then
            if [ -d "${dir}" ]; then
                chown -h "${ORA_DB_USER}":"${ORA_DB_GROUP}" "${dir}" >> "${LOG_FILE_NAME}" 2>&1
                chmod 750 "${dir}" >> "${LOG_FILE_NAME}" 2>&1
                continue
            fi
            name=""
            min_path=""
            for name in `echo "${dir}" | sed 's/\// /g'`; do
                min_path="${min_path}/${name}"
                if [ ! -d "${min_path}" ]; then
                    mkdir "${min_path}" >> "${LOG_FILE_NAME}" 2>&1
                    chown -h "${ORA_DB_USER}":"${ORA_DB_GROUP}" "${min_path}" >> "${LOG_FILE_NAME}" 2>&1
                    chmod 750 "${min_path}" >> "${LOG_FILE_NAME}" 2>&1
                fi
            done

        elif [ "`rd_substr "${dir}" 1 1`" = "+" ]; then
            # get disk group name eg: +data/orcl  return +data 
            dg_name=${dir%%/*}
            dir_length=`echo "$dir" | wc -c | $MYAWK '{print $1}'`
            dg_length=`echo "$dg_name" | wc -c | $MYAWK '{print $1}'`
            dg_name=`rd_substr "${dg_name}" 2`
            check_disk_group_exits "${dg_name}" "${ASMSIDNAME}"
            ret_code=$?
            if [ $ret_code -ne 0 ]; then
                log_error "Asm disk group ${dg_name} not exits"
                return $ret_code
            fi
            if [ "$dir_length" -eq "$dg_length" ]; then
                return
            fi
            # get child path name eg: +data/orcl/datafile  return orcl/datafile 
            child_paths=${dir#*/}
            child_paths=`echo "${child_paths}" | sed "s#/# #g"`
            tmp_dir="${dg_name}"
            for child_path_name in ${child_paths}; do
                tmp_dir="${tmp_dir}/${child_path_name}"
                check_path_in_disk_group "${tmp_dir}" "${ASMSIDNAME}"
                if [ $? -ne 0 ]; then
                    set_env_cmd=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
                    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} asmcmd mkdir ${tmp_dir}" >> "${LOG_FILE_NAME}" 2>&1
                    if [ $? -ne 0 ]; then
                        log_error "Asmcmd create dir failed, path is ${tmp_dir}"
                        return "$RETURN_INVALID"
                    fi
                fi
            done
        fi
    done
}

check_sqlplus_status()
{
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} which sqlplus" >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        log_error "Not found sqlplus canot exec sql file"
        exit "${RETURN_INVALID}"
    fi
}

check_rman_status()
{
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} which rman" >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        log_error "Not found rman canot exec rman sql file"
        exit "${RETURN_INVALID}"
    fi
}

check_mount_path()
{
    mount_path=$1
    realMountPath=`realpath "${mount_path}"`
    expr match "${realMountPath}" "${BLOCK_LIST}"
    if [ $? -eq 0 ]; then
        log_info "The mount path is in the blocklist, path is ${mount_path}."
        exit "${RETURN_INVALID}"
    fi
}

get_database_base_info()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    if [ -z "${instance_name}" ] ; then
        log_error "Instance name is none can not get mini scn"
        return "${RETURN_INVALID}"
    fi
    tmp_sql="${STMP_PATH}/get_database_base_info_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_base_info_rst_${PID}.txt"

    echo "set linesize 999" > "${tmp_sql}"
    echo "COL LOG_MODE FORMAT a20" >> "${tmp_sql}"
    echo "COL DB_UNIQUE_NAME FORMAT a20" >> "${tmp_sql}"
    echo "select a.LOG_MODE, a.DBID, a.DB_UNIQUE_NAME, a.OPEN_MODE, b.INCARNATION#, b.RESETLOGS_ID from 
    v\$database a, v\$database_incarnation b where b.STATUS='CURRENT';" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_info "Get database base info failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    cat "${tmp_rst}"
    delete_file "${tmp_sql}" "${tmp_rst}"
}

cross_check_backup_dbf()
{
    instance_name=$1
    db_name=$2
    db_user=$3
    db_password=$4

    if [ -z "${instance_name}" ] || [ -z "${db_name}" ]; then
        log_error "Instance name is none can not cross check datafile"
        return "${RETURN_INVALID}"
    fi

    upper_db_name=`echo "${db_name}" | tr '[a-z]' '[A-Z]'`
    tmp_sql="${STMP_PATH}/rman_cross_check_data_${PID}.sql"
    tmp_rst="${STMP_PATH}/rman_cross_check_data_${PID}.txt"


    echo "crosscheck datafilecopy tag 'EBACKUP-${upper_db_name}-DATA';" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    chown "${ORA_DB_USER}" "${tmp_sql}"
    chmod 700 "${tmp_sql}"

    log_info "Begin to crosscheck copy datafile"
    rman_exe_script "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 0
    ret_code=${?}
    if [ ${ret_code} -ne 0 ]; then
        log_warn "Exec corsscheck failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    log_info "Crosscheck copy datafile successful"
    delete_file "${tmp_rst}" "${tmp_sql}"
}

cross_check_archive_log()
{
    instance_name=$1
    db_name=$2
    db_user=$3
    db_password=$4
    from_scn=$5

    if [ -z "${instance_name}" ] || [ -z "${db_name}" ]; then
        log_error "Instance name is none can not cross check datafile"
        return "${RETURN_INVALID}"
    fi

    upper_db_name=`echo "${db_name}" | tr '[a-z]' '[A-Z]'`
    tmp_sql="${STMP_PATH}/rman_cross_check_log_${PID}.sql"
    tmp_rst="${STMP_PATH}/rman_cross_check_log_${PID}.txt"


    echo "crosscheck archivelog from scn ${from_scn};" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    chown "${ORA_DB_USER}" "${tmp_sql}"
    chmod 700 "${tmp_sql}"

    log_info "Begin to crosscheck archive_log "
    rman_exe_script "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 0
    ret_code=${?}
    if [ ${ret_code} -ne 0 ]; then
        log_warn "Exec corsscheck archive_log failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    log_info "Crosscheck archive_log successful"
    delete_file "${tmp_rst}" "${tmp_sql}"
}


get_datafile_mini_scn()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not get datafile mini scn"
        return "${RETURN_INVALID}"
    fi

    tmp_sql="${STMP_PATH}/get_backup_scn_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_backup_scn_rst_${PID}.txt"

    echo 'select to_char(max(CHECKPOINT_CHANGE#)) as scn from v$datafile;' > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=${?}
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get system min data file scn failed, `cat "${tmp_rst}"`."
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    backup_scn=`cat "${tmp_rst}" | tr -d " "`
    log_info "Get system min data file scn is ${backup_scn}."
    delete_file "${tmp_sql}" "${tmp_rst}"
    echo "${backup_scn}"
}


get_service_names()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    tmp_sql="${STMP_PATH}/get_service_names_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_service_names_rst_${PID}.rst"
    echo "select value from v\$parameter where name = 'service_names';" > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=${?}
    if [ ${ret_code} -ne 0 ]; then
        log_error "get service names failed, `cat "${tmp_rst}"`."
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    service_names=`cat "${tmp_rst}" | tr -d " "`
    log_info "get service name is ${service_names}."
    delete_file "${tmp_sql}" "${tmp_rst}"
    echo "${service_names}"
}


create_pfile_from_parameter()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/get_database_parameter_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_parameter_rst_${PID}.txt"
    echo "set linesize 999" > "${tmp_sql}"
    echo "COL name FORMAT a500" >> "${tmp_sql}"
    echo "select i.INSTANCE_NAME,p.NAME, p.VALUE from gv\$parameter p, gv\$instance i where isdefault !='TRUE' \
    and i.INST_ID=p.INST_ID;" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get database parameter failed, ret=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        return "${ret_code}"
    fi
    if [ -s "${tmp_rst}" ]; then
        pfile_path="${MAIN_BACKUP_PATH}/ebackup-${DBNAME}-pfile.ora"
        while read -r line
        do
            # 去掉行前后空格
            line=$(echo "$line" | xargs)
            # 跳过包含不相关信息的行
            echo "$line" | grep -Eq '^(SQL\*Plus|Copyright|Connected to:|Oracle Database|Version|Disconnected from)' && continue
            # 使用空格分隔的格式来提取实例名和参数名
            echo "$line" | grep -Eq '^[[:alnum:]]+[[:space:]]+[[:alnum:]_]+$' && {
                # 提取实例名和参数名
                instance_name=$(echo "$line" | awk '{print $1}')
                parameter_name=$(echo "$line" | awk '{print $2}')
                # 读取下一行以获取参数值
                read -r next_line
                parameter_line="$(echo "$next_line" | xargs)"
                if [[ "$parameter_line" == *","* ]] && ([ "${parameter_name}" == "db_file_name_convert" ] || [ "${parameter_name}" == "log_file_name_convert" ]); then
                    parameter_list=`echo ${parameter_line} | tr ',' '\n'`
                    line_num=`echo "$parameter_list" | wc -l | awk '{print $1}'`
                    index=0
                    echo "$parameter_list" | while IFS= read -r parameter; do
                        let index+=1
                        parameter_tmp=`echo "$parameter" | tr -d " "`
                        log_info "index is ${index}, line_num ${line_num}, parameter ${parameter_tmp} parameter_result ${parameter_result}"
                        if [ ${index} -eq 1 ]; then
                           parameter_result="'${parameter_tmp}'"
                           continue
                        fi
                        parameter_result="${parameter_result},'${parameter_tmp}'"
                        if [ ${index} -eq ${line_num} ]; then
                          echo "${instance_name}.${parameter_name}=${parameter_result}" >> "$pfile_path"
                          log_info "Creating pfile parameter: ${instance_name}.${parameter_name}=${parameter_result}"
                        fi
                    done
                else
                    parameter_value=$(echo "$next_line" | awk '{print $1}')
                    parameter_value="'${parameter_value}'"
                    echo "${instance_name}.${parameter_name}=${parameter_value}" >> "$pfile_path"
                    log_info "Creating pfile parameter: ${instance_name}.${parameter_name}=${parameter_value}"
                fi
            }
        done < "${tmp_rst}"
    else
        log_error "Create pfile from parameter failed, backup failed."
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        return "${ERROR_ORACLE_BACKUP_FAILED}"
    fi
    if [ -s "${pfile_path}" ]; then
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        log_info "Create pfile from parameter success."
    else
        log_error "Create pfile from parameter failed, backup failed."
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        return "${ERROR_ORACLE_BACKUP_FAILED}"
    fi
}

create_pfile_from_spfile()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    start_with_spfile_flag=$4

    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not create pfile"
        return "${RETURN_INVALID}"
    fi

    tmp_sql="${STMP_PATH}/create_pfile_from_spfile_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/create_pfile_from_spfile_rst_${PID}.txt"

    log_info "Create pfile from spfile by sqlplus at instance[${instance_name}]"
    if [ "${start_with_spfile_flag}" = "true" ]; then
        echo "create pfile='${MAIN_BACKUP_PATH}/ebackup-${DBNAME}-pfile.ora' from spfile;" > "${tmp_sql}"
        echo "exit" >> "${tmp_sql}"
        set_db_silence_sql "${tmp_sql}"

        oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 60 0
        ret_code=${?}
        if [ ${ret_code} -ne 0 ]; then
            log_error "Create pfile failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
            delete_file "${tmp_sql}" "${tmp_rst}"
            return ${ret_code}
        fi
    else
        create_pfile_from_parameter "${instance_name}" "${db_user}" "${db_password}"
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
}

get_copy_data_scn()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not create pfile"
        return "${RETURN_INVALID}"
    fi

    tmp_sql="${STMP_PATH}/get_copy_data_scn_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_copy_data_scn_rst_${PID}.txt"


    data_copy_path=${MAIN_BACKUP_PATH%/*}
    data_copy_path=${data_copy_path%/*}

    echo "set linesize 300;" > "$tmp_sql"
    echo "select to_char(max(CHECKPOINT_CHANGE#)), to_char(scn_to_timestamp(max(CHECKPOINT_CHANGE#)),'YYYY-MM-DD_HH24:MI:SS'), to_char(max(COMPLETION_TIME), ${TIME_FORMAT}) \
    from v\$datafile_copy where (status = 'A') and name like '${data_copy_path}/%.dbf';" >> "$tmp_sql"
    echo "exit" >> "$tmp_sql"
    set_db_silence_sql "$tmp_sql"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "Get data file scn failed,ret=${ret_code}, `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi

    dbf_scn=`cat "${tmp_rst}"| $MYAWK '{print $1}'`
    dbf_time=`cat "${tmp_rst}" | $MYAWK '{print $2}'`
    completion_time=`cat "${tmp_rst}" | $MYAWK '{print $3}'`
    dbf_timestamp=`add_unix_timestamp "$dbf_time"`
    dbf_timestamp=$(echo "${dbf_timestamp}" | tail -n 1)
    log_info "dbfSCN=${dbf_scn}  dbfTime=${dbf_time}  dbfTimeStamp=${dbf_timestamp}, completion time ${completion_time}"
    delete_file "${tmp_sql}" "${tmp_rst}"
    echo "$dbf_scn $dbf_time $dbf_timestamp"
}

redirect_backup_path()
{
    backup_path=$1
    tmp_path=${backup_path%%;*}
    if [ -d "${tmp_path}/data" ]; then
        backup=`echo "${backup_path}" | sed 's/;/ /g'`
        tmp_backup_path=""
        for i in ${backup}; do 
            tmp_backup_path="${tmp_backup_path}${i}/data;"
        done
        backup_path=${tmp_backup_path}
    fi
    echo "${backup_path}"
}

get_datafile_info()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    rst_file=$4

    if [ -z "${instance_name}" ]; then
        log_error "Instance name is none can not create pfile"
        return "${RETURN_INVALID}"
    fi

    tmp_sql="${STMP_PATH}/get_datafile_info_sql_${PID}.sql"

    echo "set linesize 999" > "${tmp_sql}"
    echo "col tsName for a30" >> "${tmp_sql}"
    echo "col tsFile for a520" >> "${tmp_sql}"
    if [ "`rd_substr "${ORA_VERSION}" 1 2`" -gt 11 ]; then
        echo "SELECT t.CON_ID CON_ID, t.Name tsName, f.File# fNo, f.Name tsFile, f.bytes/1024/1024 fMbSize FROM V\$TABLESPACE t, V\$DATAFILE f WHERE t.TS# = f.TS# and t.CON_ID = f.CON_ID order by bytes desc;" >> "${tmp_sql}"
    else
        echo "SELECT t.TS# ts, t.Name tsName, f.File# fNo, f.Name tsFile, f.bytes/1024/1024 fMbSize FROM V\$TABLESPACE t, V\$DATAFILE f WHERE t.TS# = f.TS# order by bytes desc;" >> "${tmp_sql}"
    fi
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${rst_file}" "${instance_name}" 60 1 
    ret_code=$?
    delete_file "${tmp_sql}"
    if [ ${ret_code} -ne 0 ]; then
        log_info "Get database-${instance_name} datafile list failed, ret=${ret_code}. error is `cat "${rst_file}"`"
        return ${ret_code}
    fi
}

get_dbfiles()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    fileType=$4

    tmp_sql="${STMP_PATH}/oracledbfiles${PID}.sql"
    tmp_rst="${STMP_PATH}/oracledbfilesRst${PID}.txt"
    echo "set linesize 999" > "${tmp_sql}"
    if [ "${fileType}" = "0" ]; then
        log_info "Begin to get control files ."
        echo 'select name from v$controlfile;' >> "${tmp_sql}"
    elif [ "${fileType}" = "1" ]; then
        log_info "Begin to get spfile files."
        echo "select VALUE from v\$parameter where name='spfile';" >> "${tmp_sql}"
    elif [ "${fileType}" = "2" ]; then
        log_info "Begin to get data guard configuration files."
        echo "select destination || '/*' from v\$archive_dest where destination like '/%';" >> "${tmp_sql}"    
    else
        log_error "file type ${fileType} is not supported."
        return "${RETURN_INVALID}"
    fi
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    delete_file "${tmp_sql}"
    if [ $ret_code -ne 0 ]; then
        log_error "Get oracle files failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_rst}"
        return "${RETURN_INVALID}"
    fi
    TMPLINE=`cat "${tmp_rst}"`
    delete_file "${tmp_rst}"
    echo "${TMPLINE}"
}

get_online_redo_log_info()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    rst_file=$4

    get_online_log_tmp_sql="${STMP_PATH}/get_online_log_info_${PID}.sql"
    echo "set linesize 999" > "${get_online_log_tmp_sql}"
    echo "col MEMBER for a255" >> "${get_online_log_tmp_sql}"
    echo "select GROUP#, MEMBER from v\$logfile order by GROUP#;" >> "${get_online_log_tmp_sql}"
    echo "exit;" >> "${get_online_log_tmp_sql}"
    set_db_silence_sql "${get_online_log_tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${get_online_log_tmp_sql}" "${rst_file}" "${instance_name}" 30 1
    ret_code=$?
    delete_file "${get_online_log_tmp_sql}"
    if [ "$ret_code" -ne "0" ]; then
        log_error "Get oracle online log file list failed, ret=${ret_code}, `cat "${rst_file}"`"
        return "${ret_code}"
    fi
}

get_temp_file_info()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    rst_file=$4

    get_temp_file_tmp_sql="${STMP_PATH}/get_temp_file_info_${PID}.sql"
    echo "set linesize 999" > "${get_temp_file_tmp_sql}"
    echo "col NAME for a255" >> "${get_temp_file_tmp_sql}"
    echo "select FILE#, NAME from v\$tempfile order by FILE#;" >> "${get_temp_file_tmp_sql}"
    echo "exit;" >> "${get_temp_file_tmp_sql}"
    set_db_silence_sql "${get_temp_file_tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${get_temp_file_tmp_sql}" "${rst_file}" "${instance_name}" 30 1
    ret_code=$?
    delete_file "${get_temp_file_tmp_sql}"
    if [ "$ret_code" -ne "0" ]; then
        log_error "Get oracle temp file list failed, ret=${ret_code}, `cat "${rst_file}"`"
        return "${ret_code}"
    fi
}


get_database_node_list()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    
    tmp_sql="${STMP_PATH}/get_database_node_list_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_node_rst_${PID}.txt"
    database_role=`get_db_role "${instance_name}" "${db_user}" "${db_password}"`
    echo "set linesize 300;" > "${tmp_sql}"
    if [ "${database_role}" = "PRIMARY" ]; then
      echo "select THREAD# from GV\$INSTANCE where STATUS='OPEN';" >> "${tmp_sql}"
    else
      echo "select THREAD# from GV\$INSTANCE where STATUS IN ('OPEN','MOUNTED');" >> "${tmp_sql}"
    fi
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "GetDatabaseNodeList failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return $ret_code
    fi
    cat "${tmp_rst}" 2>> "${LOG_FILE_NAME}"
    delete_file "${tmp_sql}" "${tmp_rst}"
}


get_database_node_list_standby()
{
    log_info "get_database_node_list_standby"
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/get_database_node_list_${PID}.sql"
    tmp_rst="${STMP_PATH}/get_database_node_rst_${PID}.txt"
    database_role=`get_db_role "${instance_name}" "${db_user}" "${db_password}"`
    echo "set linesize 300;" > "${tmp_sql}"
    echo "SELECT DISTINCT THREAD# from v\$archived_log;" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "GetDatabaseNodeList failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return $ret_code
    fi
    cat "${tmp_rst}" 2>> "${LOG_FILE_NAME}"
    delete_file "${tmp_sql}" "${tmp_rst}"
}

get_archive_dest_list()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    arch_dest_list=$4

    tmp_sql="${STMP_PATH}/archive_dest_sql_${PID}.sql"
    tmp_rst="${STMP_PATH}/archive_dest_rst_${PID}.txt"

    echo "set linesize 300;" > "${tmp_sql}"
    echo "col DESTINATION for a255;" >> "${tmp_sql}"
    echo "select DESTINATION from v\$archive_dest where STATUS='VALID';" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_error "Get Archive log dest list failed, msg=`cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi

    tmp_line=`cat "${tmp_rst}"`
    for line in ${tmp_line}; do
        if [ "${line}" = "USE_DB_RECOVERY_FILE_DEST" ]; then
            echo "set linesize 300;" > "${tmp_sql}"
            echo "col NAME for a255;" >> "${tmp_sql}"
            echo "select NAME from V\$RECOVERY_FILE_DEST;" >> "${tmp_sql}"
            echo "exit" >> "${tmp_sql}"
            set_db_silence_sql "${tmp_sql}"

            log_info "Exec SQL to get name of archive dest."
            oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
            ret_code=$?
            if [ "$ret_code" -ne "0" ]; then
                log_error "Get RECOVERY_FILE_DEST failed, msg=`cat "${tmp_rst}"`."
                delete_file "${tmp_sql}" "${tmp_rst}"
                return ${ret_code}
            fi
            archived_dest=`cat "${tmp_rst}"`
            log_info "STRARCHIVEDEST=${archived_dest}."
            echo "${archived_dest}" >> "${arch_dest_list}"
        elif [ -n "${line}" ]; then
            echo "${line}" >> "${arch_dest_list}"
        else
            log_warn "get line is empty, continue."
        fi
    done
    delete_file "${tmp_sql}" "${tmp_rst}"
    log_info "Get Archive Dest Lst is `cat "$arch_dest_list"`."
}

shutdown_db()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    [ -z "${instance_name}" ] && exit_with_error "DB inatance is none can not shutdown"

    tmp_sql="${STMP_PATH}/shut_down_db_sql${PID}.sql"
    tmp_rst="${STMP_PATH}/shut_down_db_rst${PID}.txt"

    echo "shutdown immediate;" > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Begin to shutdown database, instance(${instance_name})."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ] && [ $ret_code -ne $ERROR_ORACLE_NOT_OPEN ]; then
        log_error "Shutdown database [$instance_name] failed, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
}

compare_oracle_version()
{
    # $1 = $2 return 0
    # $1 > $2 return 1
    # $1 < $2 return 2
    if [ $# -ne 2 ]; then
        return 3
    fi
    version_a=$1
    version_b=$2
    log_info "$1 compare with $2"
    for num in 1 2 3 4 5 ; do
        preversion_a=`echo "$version_a" | $MYAWK -F "." -v NUM=$num '{print $NUM}'`
        preversion_b=`echo "$version_b" | $MYAWK -F "." -v NUM=$num '{print $NUM}'`
        if [ "$preversion_a" -eq "$preversion_b" ]; then
            continue
        fi
        if [ "$preversion_a" -gt "$preversion_b" ]; then
            log_info "$1 greater than $2"
            return 1
        else
            log_info "$1 lower than $2"
            return 2
        fi
    done
    log_info "$1 equal $2"
    return 0
}

get_controlfile_path_list()
{
    instance_name=$1
    db_user=$2
    db_password=$3


    tmp_sql="${STMP_PATH}/get_controlfile_path_list${PID}.sql"
    tmp_rst="${STMP_PATH}/get_controlfile_path_list${PID}.rst"

    echo "set linesize 600" > "$tmp_sql"
    echo "select name from v\$controlfile;" >> "$tmp_sql"
    echo "exit" >> "$tmp_sql" 
    set_db_silence_sql "$tmp_sql"

    log_info "Exec SQL to get control files of database."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    RET=$?
    if [ $RET -ne 0 ]; then
        log_error "Query control file database(${instance_name}) file failed, ret_code=$RET"
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${RET}
    fi

    file_list=`cat "${tmp_rst}"`
    delete_file "${tmp_sql}" "${tmp_rst}"

    control_files=$(for p in ${file_list}; do printf \'$p\',; done | sed 's/,$//')
    echo "$control_files"
}

set_controlfile_path_list()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    control_files=$4

    tmp_sql="${STMP_PATH}/get_controlfile_path_list${PID}.sql"
    tmp_rst="${STMP_PATH}/get_controlfile_path_list${PID}.rst"
    
    echo "startup nomount" > "${tmp_sql}"
    echo "alter system set control_files=$control_files scope=spfile;" >> "${tmp_sql}"
    echo "shutdown immediate;" >> "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "$tmp_sql"

    log_info "Exec SQL to set control files."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 0 
    ret_code=$?
    if [ "$ret_code" -ne "0" ] && [ $ret_code -ne $ERROR_ORACLE_NOT_OPEN ] && [ $ret_code -ne $ERROR_ORACLE_NOT_MOUNTED ]; then
        log_error "SQL to set database(${DBINSTANCE}) control files fail, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
}


# need ${LOGIN_AUTH} ${QUERYCDBSCRIPT} ${QUERYCDBSCRIPTRST}
#           ${QUERYCDBSCRIPT} ${QUERYCDBSCRIPTRST}
# $1 $ORA_INSTANCENAME
# return 
# 1- not CDB
# 0- CDB
# else error code
#
check_database_cdb_type()
{    
    instance_name=$1
    db_user=$2
    db_password=$3
    ORACLE_IS_CDB=1
    #get Oracle version and check if it's 12
    if [ "$ORA_PREVERSION" -lt "12" ];then
        log_info "Oracle version($ORA_VERSION) not supports CDB."
        return 1
    fi

    tmp_sql="$STMP_PATH/check_oracle_cdb_type_$PID.sql"
    tmp_rst="$STMP_PATH/check_oracle_cdb_type_$PID.rst"
    #get CDB type
    echo "select cdb from v\$database;" > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Exec SQL to get CDB type of instance."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 30 1
    ret_code=$?
    if [ "${ret_code}" -ne "0" ]; then
        log_error "Get database cdb type failed, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return
    fi
    cdb_type=`cat "${tmp_rst}"`
    log_info "ORACLECDBTYPE=${cdb_type}."
    delete_file "${tmp_sql}" "${tmp_rst}"

    if [ "${cdb_type}" = "YES" ]; then
        ORACLE_IS_CDB=0
        log_info "The instance [$instance_name] is a CDB"
        return
    fi
    ORACLE_IS_CDB=1
    log_info "The instance [$instance_name] not is a CDB"
}

open_all_pdbs()
{    
    instance_name=$1
    db_user=$2
    db_password=$3
    tmp_sql="${STMP_PATH}/open_all_pdbs${PID}.sql"
    tmp_rst="${STMP_PATH}/open_all_pdbs${PID}.rst"

    echo "alter pluggable database all open;" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_info "Open PDB failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
    log_info "Open PDB succ."
}

modify_cluster_property()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    status=$4

    tmp_sql="${STMP_PATH}/TEMP${PID}.sql"
    tmp_rst="${STMP_PATH}/TEMPRST${PID}.txt"


    echo "alter system set cluster_database=$status scope=spfile;" > "${tmp_sql}"
    echo "shutdown immediate;" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Begin to modify cluster property."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ] && [ ${ret_code} -ne 41 ] ;then
        log_info "Modify cluster-${DBINSTANCE} failed, error=${ret_code}."
        cat "${tmp_rst}" >> "${LOG_FILE_NAME}"
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${ret_code}
    fi
    log_info "Modify cluster-${DBINSTANCE} succ."
    delete_file "${tmp_sql}" "${tmp_rst}"
}

start_mount()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/TEMP${PID}.sql"
    tmp_rst="${STMP_PATH}/TEMPRST${PID}.txt"

    echo "startup mount" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "Alter database mount failed, ret=${ret_code}, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${ret_code}
    fi
    log_info "Alter database mount success."
    delete_file "${tmp_sql}" "${tmp_rst}"
}

start_open()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/StartDB${PID}.sql"
    tmp_rst="${STMP_PATH}/DtartDBRST${PID}.txt"

    echo "startup;" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Begin to start DB."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        errmsg=`cat "${tmp_rst}"`
        if echo "$errmsg" | grep -q "already-running ORACLE" > /dev/null; then
            log_info "DB is already running."
        else
            log_info "Start DB failed, ret=$ret_code, errmsg=`cat "${tmp_rst}"`."
            delete_file "${tmp_sql}" "${tmp_rst}"
            exit ${ret_code}
        fi
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
    log_info "Start DB succ."
}

write_error_info_to_file()
{
    ERRDETAIL_FILE="${STMP_PATH}/result_errordetail${PID}"
    rm -rf "${ERRDETAIL_FILE}"
    if [ ! -f "$1" ]; then
        log_error "Result file not exit canot not wirte error info file"
    fi
    line=
    while read line; do
        echo "${line}" | grep "RMAN-*"
        if [ $? -eq 0 ]; then
            echo "${line}" >> "${ERRDETAIL_FILE}"
        fi
        echo "${line}" | grep "ORA-*"
        if [ $? -eq 0 ]; then
            echo "${line}" >> "${ERRDETAIL_FILE}"
        fi
    done < "$1"
}

shut_down_db()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/shutdown_${PID}.sql"
    tmp_rst="${STMP_PATH}/shutdown_${PID}.txt"
    echo "shutdown immediate;" > "${tmp_sql}"
    echo "exit" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Begin to shutdown database, instance(${DB_SID})."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ] && [ $ret_code -ne $ERROR_ORACLE_NOT_OPEN ]; then
        log_error "Shutdown database failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
}

check_omf_eable()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    OMF_ENABLE=0
    tmp_sql="${STMP_PATH}/check_omf_${PID}.sql"
    tmp_rst="${STMP_PATH}/check_omf_${PID}.rst"
    echo "set linesize 300" > "${tmp_sql}"
    echo "select value from v\$parameter where name='db_create_file_dest';" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_error "Check OMF Enable failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${ret_code}
    fi

    omf_path=`cat "${tmp_rst}"`
    if [ -n "${omf_path}" ]; then
        log_info "OMF path is ${omf_path}, OMF is enable"
        OMF_ENABLE=1
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
}

stop_single_instance()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/stop_single_instance_$PID.sql"
    tmp_rst="${STMP_PATH}/stop_single_instance_$PID.rst"
    HAVEPROCESS=`ps -aef | grep -v grep | sed 's/ *$//g' | grep "ora_...._$instance_name$" | wc -l | $MYAWK '{print $1}'`
    if [ "$HAVEPROCESS" -ne "0" ]; then
        # **************************Create ShutDown DataBase Sql****************************************
        echo "shutdown abort;" > "$tmp_sql"
        echo "exit" >> "$tmp_sql"
        set_db_silence_sql "$tmp_sql"
        log_info "Exec SQL to shutdown database."
        oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 60 1 
        ret_code=$?
        delete_file "${tmp_sql}"
        if [ "${ret_code}" -eq "${ERROR_ORACLE_NOT_OPEN}" ]; then
            log_info "Shutdown database(${DBINSTANCE}) have already shutdown."
        elif [ "${ret_code}" -ne "0" ]; then
            log_error "Shutdown database(${DBINSTANCE}) file failed, errorcode=${ret_code}, error:`cat "${tmp_rst}"`."
            delete_file "${tmp_rst}"
            exit ${ret_code}
        else
            log_info "Shutdown database successful."
        fi
        delete_file "${tmp_sql}" "${tmp_rst}"
    else
        log_info "The Instance isn't Started."
    fi
}

get_pdb_name_by_conid()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    CON_ID=$4
    if [ "$CON_ID" -ne 1 ]; then
        pdb_sql="${STMP_PATH}/PDBName${PID}.sql"
        pdb_rst="${STMP_PATH}/PDBNameRST${PID}.txt"
        echo "select name from v\$pdbs where con_id='${CON_ID}';" > "${pdb_sql}"
        echo "exit" >> "${pdb_sql}"
        set_db_silence_sql "${pdb_sql}"
        oracle_exe_sql "${db_user}" "${db_password}" "${pdb_sql}" "${pdb_rst}" "${instance_name}" 60 1 
        ret_code=$?
        if [ ${ret_code} -ne 0 ]; then
            delete_file "${pdb_sql}" "${pdb_rst}"
            log_error "Exec SQL to get PDB name by con_id failed, ret=${ret_code}., error is `cat "${pdb_rst}"`"
            exit ${ret_code}
        fi
        ORA_PDB_NAME=`cat "${pdb_rst}"`
        delete_file "${pdb_sql}" "${pdb_rst}"
    else
        ORA_PDB_NAME="CDB\$ROOT"
    fi
    return 0
}

get_db_role()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    db_role_tmp_sql="${STMP_PATH}/database_role_${PID}.sql"
    db_role_tmp_rst="${STMP_PATH}/database_role_${PID}.rst"
    echo "select database_role from v\$database;" > "${db_role_tmp_sql}"
    echo "exit;" >> "${db_role_tmp_sql}"
    set_db_silence_sql "${db_role_tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${db_role_tmp_sql}" "${db_role_tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ $ret_code -ne 0 ]; then
        log_error "Query database role failed, ret=$ret_code, error is `cat "${db_role_tmp_rst}"`"
        delete_file "${db_role_tmp_sql}" "${db_role_tmp_rst}"
        return $ret_code
    fi
    DATABASE_ROLE="`cat "${db_role_tmp_rst}"`"
    log_info "Database role:${DATABASE_ROLE}."
    delete_file "${db_role_tmp_sql}" "${db_role_tmp_rst}"
    echo "${DATABASE_ROLE}"
}

check_database_password()
{
    db_user=$1
    db_pwd=$2
    # only oracle can modify sql_file file
    sql_file=$3
    # only root can modify rst file
    rst_file=$4
    instance_name=$5
    # execute sql timeout -1 is not limit
    timeout_second=$6
    # 静默模式只显示结果信息
    is_silence=$7
    if [ "${is_silence}" -eq 1 ]; then
        silent_mode="-S"
    fi
    sqlplus_timeout "${timeout_second}"
    # 提取到外面进行 函数呢不做修改文件权限 oracle必须要有权限读取权限

    set_env_cmd=`generate_export_oracle_sid "${instance_name}"`
    echo \"${db_pwd}\" | su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${set_env_cmd} sqlplus -L ${silent_mode} '${db_user} as sysdba' @'${sql_file}' " >"${rst_file}" 2>&1
    result_code=$?
    delete_oracle_mark "${rst_file}"
    # ~/.bash_profile 配置了stty erase ^H 时执行sql会出现stty:开头的内容
    if [ ${result_code} -eq 0 ]; then
        sed -i '/^stty:/d' "${rst_file}"
    fi
    # 因为密码是输入进去的，会导致结果文件第一行为空行
    sed '1d' "${rst_file}" >"${rst_file}".bak
    mv "${rst_file}".bak "${rst_file}"
    if [ ${result_code} -ne 0 ]; then
        log_error "Execute oracle sqlplus cmd failed, cmd ret code ${result_code}"
        result_code=$ERROR_SCRIPT_EXEC_FAILED
    fi
    cat ${rst_file} > /tmp/rst_file.txt
    get_sql_error_info "${rst_file}" "$result_code" 1
    return $?
}

delete_oracle_mark()
{
    tmp_file=$1
    if [ "${SYS_NAME}" = "AIX" ]; then
        #aix sed从0开始不生效，需要加1行从1开始
        echo 'Aix_FLAG' >"${tmp_file}".bak
        cat "${tmp_file}" >>"${tmp_file}".bak
        sed '1,/\/###ORACLE_MARK###\//d' "${tmp_file}".bak >"${tmp_file}"
        delete_file "${tmp_file}".bak
    else
        sed '0,/\/###ORACLE_MARK###\//d' "${tmp_file}" >"${tmp_file}".bak
        mv "${tmp_file}".bak "${tmp_file}"
    fi
}

check_list_is_consecutive()
{
    list=$1
    expected=${list[0]}
    is_consecutive=1
    for list_num in ${list}; do
        log_info "list_num ${list_num}, expected ${expected}."
        if [ "$list_num" -ne "$expected" ]; then
            is_consecutive=0
            break
        fi
        expected++
    done
    echo "${is_consecutive}"
}